import { is_object, objKeys } from '@dataui/crud-util';
import {
  Any,
  ArrayContainedBy,
  ArrayContains,
  ArrayOverlap,
  Between,
  Equal,
  ILike,
  FindOperator,
  FindOptionsWhere,
  In,
  IsNull,
  LessThan,
  LessThanOrEqual,
  Like,
  MoreThan,
  MoreThanOrEqual,
  Not,
} from 'typeorm';
import { FindOperatorReq, FindOptionsWhereReq, isFindOperatorReq } from '../find-options';
interface _entity {
  field: string | number | boolean | object;
}
function transOperator(findOperator: FindOperatorReq<any>): FindOperator<any> {
  let ormFindOperator: FindOperator<any>;
  const value = findOperator.v;
  switch (findOperator.t) {
    case 'any':
      ormFindOperator = Any(value);
      break;
    case 'arrayContainedBy':
      ormFindOperator = ArrayContainedBy(value);
      break;
    case 'arrayContains':
      ormFindOperator = ArrayContains(value);
      break;
    case 'arrayOverlap':
      ormFindOperator = ArrayOverlap(value);
      break;
    case 'between':
      if (Array.isArray(value) && value.length === 2) {
        ormFindOperator = Between(value[0], value[1]);
      }
      break;
    case 'equal':
      ormFindOperator = Equal(value);
      break;
    case 'ilike':
      ormFindOperator = ILike(value);
      break;
    case 'in':
      ormFindOperator = In(value);
      break;
    case 'isNull':
      ormFindOperator = IsNull();
      break;
    case 'lessThan':
      ormFindOperator = LessThan(value);
      break;
    case 'lessThanOrEqual':
      ormFindOperator = LessThanOrEqual(value);
      break;
    case 'like':
      ormFindOperator = Like(value);
      break;
    case 'moreThan':
      ormFindOperator = MoreThan(value);
      break;
    case 'moreThanOrEqual':
      ormFindOperator = MoreThanOrEqual(value);
      break;
    case 'not':
      if (isFindOperatorReq(value)) {
        ormFindOperator = Not(transOperator(value));
      } else {
        ormFindOperator = Not(value);
      }
      break;
    case 'raw':
      break;

    default:
      break;
  }
  return ormFindOperator;
}

export function transWhere<T = any>(_where: FindOptionsWhereReq<T>, ormWhere: FindOptionsWhere<T>) {
  const where = _where as FindOptionsWhereReq<_entity>;
  objKeys(where).forEach((field) => {
    const whereValue = where[field as keyof _entity];
    if (!is_object(whereValue)) {
      ormWhere[field] = whereValue;
    } else if (isFindOperatorReq(whereValue)) {
      ormWhere[field] = transOperator(whereValue);
    } else {
      if (Array.isArray(whereValue)) {
        ormWhere[field] = whereValue;
      } else {
        ormWhere[field] = {};
        transWhere(whereValue, ormWhere[field]);
      }
    }
  });
}
